package com.mew.slots.core.common.roller.xml;


import com.mew.common.util.RollerDownUtils;
import com.mew.common.util.StringUtils;
import lombok.Data;
import lombok.ToString;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.*;

@Data
@ToString
public abstract class BaseXml {

    public Integer row;
    public Integer col;

    //根路径
    public String rootpath = System.getProperty("user.dir");

    public ArrayList<String> paths = new ArrayList<>();
    public String bigWinPath;

    public HashMap<Integer, HashMap<Integer,ArrayList<ArrayList<Integer>>>> allRollers = new HashMap<>();

    //返回线
    public  ArrayList<Integer> getLine(int path,int rollerID){

        Integer row = this.getRow();
        Integer col = this.getCol();

        //返回的线
        Integer[] lines = new Integer[row*col];

        for (int i = 0; i < col; i++) { //row 3 col 5
            ArrayList<Integer> line = this.getAllRollers().get(path).get(rollerID).get(i);

            //第i条线的
            int start = (int)( Math.random()*(line.size()));
            for (int j = 0; j < row; j++) {
                if (start==-1){
                    start = line.size()-1;
                }
                lines[i+ col *j] =  line.get(start--);
            }
        }

        return new ArrayList<Integer>(Arrays.asList(lines));
    }

    public int[] getLineInts(int path,int rollerID){
        return getLine(path,rollerID).stream().mapToInt(Integer::intValue).toArray();
    }
    public  boolean canParseInt(String str){
        if(str == null){ //验证是否为空
            return false;
        }
        return str.matches("\\d+"); //使用正则表达式判断该字符串是否为数字，第一个\是转义符，\d+表示匹配1个或 //多个连续数字，"+"和"*"类似，"*"表示0个或多个
    }

    /**
     * xml解出的str数组转成int数组
     * @param strs
     * @return
     */
    public  ArrayList<Integer> str2int(ArrayList<String> strs){
        ArrayList<Integer> ints = new ArrayList<>();
        for (String str : strs) {
            if (canParseInt(str)){
                ints.add(Integer.parseInt(str));
            }else {
                ints.add(parseInt(str));
            }
        }
        return ints;
    };

    /**
     * 子类复写  例：W转成9
     * @param str
     * @return
     */
    public abstract int parseInt(String str);


    /**
     * 初始化所有
     * @throws Exception
     */
    public void init() throws Exception{
        //初次读
        if (null==allRollers||allRollers.isEmpty()){
            initPathsRowCol();
            downXml();
        }
        xml2Roller();
    }

    /**
     * 初始化
     * 轴路径
     * 几行几列
     * @return
     */
    public abstract void initPathsRowCol() throws Exception;


    private void xml2Roller() throws DocumentException {
        int pathIdx = 0;
        for (String path : this.getPaths()) {
            //地址
            File file = new File(rootpath + File.separator + path);
            if(file.exists()) {
                HashMap<Integer, ArrayList<ArrayList<Integer>>> arrayLists = xml2roller(file);
                this.allRollers.put(pathIdx, arrayLists);
            }
            pathIdx++;
        }
    }

    /**
     * 解析路径
     * @param file
     * @throws DocumentException
     */
    public  HashMap<Integer,ArrayList<ArrayList<Integer>>> xml2roller(File file) throws DocumentException {
        //返回的
        HashMap<Integer,ArrayList<ArrayList<Integer>>> rollers = new HashMap<>();

        SAXReader reader = new SAXReader();
        Document document = reader.read(file);

        //Config
        String root = "/Config";
        Element rootNode = (Element)document.selectSingleNode(root);

        //roller

        for (Iterator it = rootNode.elementIterator(); it.hasNext();){

            Element rollerNode = (Element) it.next();
            Integer rollerIdx = Integer.parseInt(rollerNode.attributeValue("RollerID"));

            ArrayList<ArrayList<Integer>> roller = new ArrayList<>();
            //Line
            for (Iterator itRo = rollerNode.elementIterator();itRo.hasNext();){
                Element node = (Element) itRo.next();

                String value = node.getStringValue();
                value = value.replaceAll("\\s*","");
                value = value.replaceAll("\"","");
                String[] split = value.split(",");

                //得到解析List
                ArrayList<Integer> line = str2int(new ArrayList(Arrays.asList(split))) ;
                roller.add(line);
            }
            rollers.put(rollerIdx,roller);
        }
        file.delete();
        return rollers;
    }

    /**
     * 不存在就下载
     * @throws Exception
     */
    public void downXml() throws Exception{

        for (String path0 : this.getPaths()) {
            int li = path0.lastIndexOf("/");
            String div = path0.substring(0, li);

            File divfile = new File(rootpath + File.separator + div);
            //文件夹是否存在
            if ( !divfile.exists()){
                divfile.mkdir();
            }

            File file = new File(path0);
            if (StringUtils.isNotEmpty(path0) && !file.exists()){
                //下载轴
                RollerDownUtils.downXml(path0);
            }
        }
    }

    /**
     * 报错下载
     * @throws Exception
     */
    public void errXml() throws Exception{

        for (String path0 : this.getPaths()) {
            int li = path0.lastIndexOf("/");
            String div = path0.substring(0, li);

            File divfile = new File(rootpath + File.separator + div);
            //文件夹是否存在
            if ( !divfile.exists()){
                divfile.mkdir();
            }

            File file = new File(path0);
            if (StringUtils.isNotEmpty(path0)){
                //下载轴
                RollerDownUtils.downXml(path0);
            }
        }
    }
    /**下落取消获取一条线
     * @param path 使用的轴策略(保存xml轴路径数组的下标)
     * @param rollerID 轴策略ID
     * @param idex 当前线策略使用的下标
     * @param res 轴集合
     */
    public int[] getDownLine(int path, int rollerID, Integer[] idex, int[] res) {
        //图标掉落
        iconDown(res);
        for (int i = 0; i < col; i++) {

            ArrayList<Integer> line = this.getAllRollers().get(path).get(rollerID).get(i);
            //第i条线 应该使用的
            Integer idex1 = idex[i];

            //第一次进入 没有使用线策略.随机一个数字取线策略的值
            int start =null==idex1 ? (int)( Math.random()*(line.size())) : idex1;
            for (int j = row-1; j >-1; j--) {
                //为空才填进去
                if (-1==res[i+col*j]){
                    start += 1;
                    if (start>line.size()-1){
                        start = 0;
                    }
                    res[i+col*j] =  line.get(start);
                }
            }
            idex[i] = start;
        }
        return res.clone();
    }
    /**循环每列 从下到上进行掉落(dowm方法实现掉落下移)
     *     当前轴数组
     *                 1,  2,  3,  1,  2
     *                 2, null,3,  2,  2
     *                 4,  3,  2, null,1
     *     下落后数组
     *                  1, null,3, null,2
     *                  2,  2,  3,  1,  2
     *                  4,  3,  2,  2,  1
     * @param res 当前轴数组
     */
    public  void iconDown(int[] res){
        for (int i = 0; i < col ; i++) {
            dowm(res,row*col-i-1 );
        }
    }
    /**掉落下移
     * @param res 当前轴数组
     * @param idx 开始计算位置
     */
    private  void dowm(int[] res,int idx) {
        //位置小于0  计算完毕
        if (idx<0){
            return ;
        }
        //一行5个图标 所以小于10代表数据为最后一列 不用计算
        if (idx<col*(row-1)){
            //掉落 如果当前位置有图标.同列下一个图标被消除.当前图标下落填充

            Integer nextIcon = res[idx+col];
            Integer icon = res[idx];

            if (-1==nextIcon && -1!=icon){
                res[idx+col]=icon;
                res[idx]=-1;

                if (idx+col<row*col){
                    dowm(res,idx+col);
                    return;
                }
            }

        }
        //递归计算直到完毕
        dowm(res,idx-col);
    }
}
